package us.gaaoc.framework.webapp.controllers;

import java.awt.Color;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import us.efiling.gaje2.conf.LdapSettings;
import us.gaaoc.framework.dao.ModelFacade;
import us.gaaoc.framework.model.DocumentBinaries;
import us.gaaoc.framework.model.DocumentStatus;
import us.gaaoc.framework.model.Documents;
import us.gaaoc.framework.model.LdapDirectoryPerson;
import us.gaaoc.framework.model.Person;
import us.gaaoc.framework.model.constants.Constants;
import us.gaaoc.framework.model.constants.Constants.Roles;
import us.gaaoc.framework.signature.digital.DigitalSignerController;
import us.gaaoc.framework.signature.digital.ldap.LdapClient;

import com.lowagie.text.DocumentException;
import com.lowagie.text.Image;
import com.lowagie.text.pdf.BaseFont;
import com.lowagie.text.pdf.PdfContentByte;
import com.lowagie.text.pdf.PdfReader;
import com.lowagie.text.pdf.PdfStamper;

/**
 * Controller which exposes POST/AJAX endpoints for modifying PDF documents.
 * 
 * @author artripa
 *
 */
@Controller
@Transactional
public class DocumentSignatureController {
	
	@Autowired ModelFacade modelFacade;
	@Autowired LdapSettings ldapSettings;
	
	Logger log = Logger.getLogger(DocumentSignatureController.class);
	
	protected byte[] addText(byte[] contents,String text,float x,float y,int page,boolean under) throws IOException, DocumentException 
	{
		PdfContentByte stampDest;
		
		ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
		PdfReader reader = new PdfReader(contents);
		
		PdfStamper stamp = new PdfStamper(reader,byteArrayOutputStream);
		BaseFont bf = BaseFont.createFont(BaseFont.HELVETICA,BaseFont.WINANSI, BaseFont.EMBEDDED);
		

		float xpos = x;//(float)reader.getPageSize(page).getWidth()*x;
		float ypos = y;//(float)reader.getPageSize(page).getHeight()*y;
		
		log.debug("Stamping at " + xpos + " " + ypos);
		
		if(under == true){		
			stampDest = stamp.getUnderContent(page);			
		}else{
			stampDest = stamp.getOverContent(page);
		}
		stampDest.beginText();
		stampDest.setFontAndSize(bf, 11);
		stampDest.setColorFill(new Color(148, 0, 219));
		stampDest.showTextAligned(PdfContentByte.ALIGN_CENTER, text, xpos,ypos, (float) 0.0);
		
		stamp.close();
		reader.close();
					
		byte[] ret = byteArrayOutputStream.toByteArray();
		byteArrayOutputStream.close();	
		
		return ret;
	}
	
	protected byte[] addStamp(byte[] contents,Image img,float x,float y,int page,boolean under) throws IOException, DocumentException 
	{
		PdfContentByte stampDest;
		
		ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
		PdfReader reader = new PdfReader(contents);
		
		PdfStamper stamp = new PdfStamper(reader,byteArrayOutputStream);
		BaseFont bf = BaseFont.createFont(BaseFont.HELVETICA,BaseFont.WINANSI, BaseFont.EMBEDDED);
		

		float xpos = x;//(float)reader.getPageSize(page).getWidth()*x;
		float ypos = y;//(float)reader.getPageSize(page).getHeight()*y;
		
		log.debug("Stamping at " + xpos + " " + ypos);
		
		if(under == true){		
			stampDest = stamp.getUnderContent(page);			
		}else{
			stampDest = stamp.getOverContent(page);
		}
		stampDest.addImage(img,img.getWidth(),0,0,img.getHeight(), xpos,ypos);
		
		stamp.close();
		reader.close();
		
		byte[] ret =byteArrayOutputStream.toByteArray();
		
		byteArrayOutputStream.close();		
		return ret;
	}
	
    public static byte[] getBytesFromFile(File file) throws IOException {
        InputStream is = new FileInputStream(file);
    
        // Get the size of the file
        long length = file.length();
    
        if (length > Integer.MAX_VALUE) {
            // File is too large
        }
    
        // Create the byte array to hold the data
        byte[] bytes = new byte[(int)length];
    
        // Read in the bytes
        int offset = 0;
        int numRead = 0;
        while (offset < bytes.length
               && (numRead=is.read(bytes, offset, bytes.length-offset)) >= 0) {
            offset += numRead;
        }
    
        // Ensure all the bytes have been read in
        if (offset < bytes.length) {
            throw new IOException("Could not completely read file "+file.getName());
        }
    
        // Close the input stream and return bytes
        is.close();
        return bytes;
    }
	

    @RequestMapping(value="/textdocument",method=RequestMethod.POST)
    public String textDocument(
    		HttpSession session,
    		@RequestParam("text") String text,
			@RequestParam("document") String documentId, 
			@RequestParam("page") int pageNumber,
			@RequestParam("x") int xPosition,
			@RequestParam("y") int yPosition) throws IOException, DocumentException
	{
    	Person p = (Person) session.getAttribute("person");
    	Documents document = (Documents) modelFacade.getSession().get(Documents.class,documentId);		
		document.setContent(p,addText(document.getContent(),text,xPosition,yPosition,pageNumber,true));
    	return "/index.html";
    }
    
    @RequestMapping(value="/undodocument",method=RequestMethod.POST)
    public String undo(    		
    		HttpSession session,	
			@RequestParam("document") String documentId) throws IOException, DocumentException
	{
    	Person p = (Person) session.getAttribute("person");
    	Documents document = (Documents) modelFacade.getSession().get(Documents.class,documentId);		
		
    	List<DocumentBinaries> dbList =
    			modelFacade.getSession().createQuery("from DocumentBinaries db where db.metaDataUuid = :doc").setParameter("doc",document)
    		.list();
    	
    	DocumentBinaries db =  dbList.get(dbList.size()-1);
    	if(db != null && db.getPerson() != null && db.getPerson().getUuid().equals(p.getUuid()) && dbList.size() > 1)  {
    		new File(db.getPath()).delete();
    		modelFacade.getSession().delete(db);
    	}
    	    	
    	return "/index.html";
    }
    
	@RequestMapping(value="/currentdateLong",method=RequestMethod.POST)
	public String addCurrentDate(
			HttpSession session,		
			@RequestParam("document") String documentId, 
			@RequestParam("page") int pageNumber,
			@RequestParam("x") int xPosition,
			@RequestParam("y") int yPosition) throws IOException, DocumentException
	{
		
		Person p = (Person) session.getAttribute("person");
		String text;
		
		Date d = new Date();
		
		
		text = "This the " + 
				new SimpleDateFormat("dd").format(d) + " " +
				" day of " +
				new SimpleDateFormat("MMMMM").format(d) + ", " + 
				new SimpleDateFormat("yyyy").format(d);
		
		Documents document = (Documents) modelFacade.getSession().get(Documents.class,documentId);
		document.setContent(p,addText(document.getContent(),text,xPosition,yPosition,pageNumber,true));
		return "/index.html";
	}
	
	@RequestMapping(value="/currentdateMonthYear",method=RequestMethod.POST)
	public String addCurrentDateMY(
			HttpSession session,		
			@RequestParam("document") String documentId, 
			@RequestParam("page") int pageNumber,
			@RequestParam("x") int xPosition,
			@RequestParam("y") int yPosition) throws IOException, DocumentException
	{
		
		Person p = (Person) session.getAttribute("person");
		String text;
		
		Date d = new Date();
		
		
		text = 	new SimpleDateFormat("MMMMM").format(d) + ", " + 
				new SimpleDateFormat("yyyy").format(d);
		
		Documents document = (Documents) modelFacade.getSession().get(Documents.class,documentId);
		document.setContent(p,addText(document.getContent(),text,xPosition,yPosition,pageNumber,true));
		return "/index.html";
	}
	
	@RequestMapping(value="/currentdateDay",method=RequestMethod.POST)
	public String addCurrentDateDay(
			HttpSession session,		
			@RequestParam("document") String documentId, 
			@RequestParam("page") int pageNumber,
			@RequestParam("x") int xPosition,
			@RequestParam("y") int yPosition) throws IOException, DocumentException
	{
		
		Person p = (Person) session.getAttribute("person");
		String text;
		
		Date d = new Date();
		
		text = 	new SimpleDateFormat("dd").format(d);
		
		Documents document = (Documents) modelFacade.getSession().get(Documents.class,documentId);
		document.setContent(p,addText(document.getContent(),text,xPosition,yPosition,pageNumber,true));
		return "/index.html";
	}
	@RequestMapping(value="/signdocument",method=RequestMethod.POST)
		public String signDocument(
				HttpSession session,		
				@RequestParam("document") String documentId, 
				@RequestParam("page") int pageNumber,
				@RequestParam("x") int xPosition,
				@RequestParam("y") int yPosition) throws IOException, DocumentException
	{
		
		Person p = (Person) session.getAttribute("person");
		LdapDirectoryPerson ld = this.modelFacade.findLdapDirectoryByPerson(p);
		LdapClient client = new LdapClient();
		client.setSettings(ldapSettings);
		Image img = client.retrieveSignatureImage(ld.getCname());
		
		Documents document = (Documents) modelFacade.getSession().get(Documents.class,documentId);
		document.setContent(p,addStamp(document.getContent(),img,xPosition,yPosition,pageNumber,true));
		return "/index.html";
	}
	
	@RequestMapping(value="/finish",method=RequestMethod.POST)
	public String finish(
			HttpSession session,
			HttpServletRequest req,
			@RequestParam("document") String documentId
			) throws Exception
	{
		Person p = (Person) session.getAttribute("person");
		Documents document = (Documents) modelFacade.getSession().get(Documents.class,documentId);
		DigitalSignerController digitalSignerController = new DigitalSignerController();		
		byte[] sigInByte = null;
		LdapDirectoryPerson ldPerson = modelFacade.findLdapDirectoryByPerson(p);
		
		//sigInByte = digitalSignerController.signDocument(document, p,p.getRoles().get(0).getUuid(), ldPerson);
		sigInByte = digitalSignerController.signDocument(document, p,p.getRoles().get(0).getUuid());
		
		// update the signed field in the documents object
		DocumentStatus documentStatus  = new DocumentStatus();
		
		if(digitalSignerController.isSignedDoc() == true) {
			
			
			int statusCode = Constants.DocumentStatus.SIGNED_BY_ATTORNEY;			//signedByAttorney
			
			if(p.getRoles().get(0).getUuid().equals(Roles.CLERKID))
			{
				statusCode = Constants.DocumentStatus.SIGNED_BY_CLERK;
			}
			
			documentStatus = this.modelFacade.findDocumentStatus(statusCode);
			digitalSignerController.updateDatabaseAfterSigned(document,
					documentStatus, p, sigInByte);
		}
		
		if(p.getRoles().get(0).getUuid().equals(Roles.ATTORNEYID))
		{
			return "redirect:/secure/attorney/childEnforcement/childEnforcementCaseDetailsPage.faces";
		}else if(p.getRoles().get(0).getUuid().equals(Roles.CLERKID))
		{
			return "redirect:/secure/clerk/childEnforcement/childEnforcementCaseDetailsPage.faces";
		}
		return "";		
	}
	
}
